package security.core.manager;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import security.core.source.UserDetail;
import security.core.source.service.PermissionSourceService;
import security.core.source.service.RoleSourceService;
import security.debug.RBACLogger;

public class PrivilegeManager {
	private String accessDeniedPage;
	private PermissionSourceService permissionSourceService;
	private RoleSourceService roleSourceService;
	private Map<String, Set<String>> resourceRolesMap;
	
	public Map<String, Set<String>> loadResourceRolesMap() {
		if (RBACLogger.debug()) {
			RBACLogger.log("PrivilegeManager#loadResourceRolesMap is called!");
		}
		Map<String, Set<String>> rolePermissionsMap = roleSourceService.getRolePermissionsMap();
		Map<String, Set<String>> permissionResourcesMap = permissionSourceService.getPermissionResourcesMap();
		// TODO
		if (shouldLoadMap()) {
			resourceRolesMap = new HashMap<String, Set<String>>();
			for (String role : rolePermissionsMap.keySet()) {
				Set<String> permissions = rolePermissionsMap.get(role);
				for (String permission : permissions) {
					for (String resource : permissionResourcesMap.get(permission)) {
						if (resourceRolesMap.containsKey(resource)) {
							resourceRolesMap.get(resource).add(role);
						} else {
							Set<String> roles = new HashSet<String>();
							roles.add(role);
							resourceRolesMap.put(resource, roles);
						}
					}
				}
			}
		}
		return resourceRolesMap;
	}
	
	public boolean isAuthorizedRequest(UserDetail user, String requestURL) {
		if (RBACLogger.debug()) {
			RBACLogger.log("PrivilegeManager#isAuthorizedRequest is called!");
		}
		Map<String, Set<String>> resourceRoles = loadResourceRolesMap();
		Set<String> requestRoles = new HashSet<String>();
		for (String resourcePattern : resourceRoles.keySet()) {
			if (Pattern.matches(resourcePattern, requestURL)) {
				requestRoles.addAll(resourceRoles.get(resourcePattern));
			}
		}
		if (requestRoles.isEmpty()) {
			return true;
		}
		Set<String> authorizedRoles = new HashSet<String>(user.getAuthorisedRoles());
		if (RBACLogger.debug()) {
			RBACLogger.log("\tauthorizedRoles:");
			System.out.println(authorizedRoles);
			RBACLogger.log("\trequestRoles:");
			System.out.println(requestRoles);
		}
		authorizedRoles.retainAll(requestRoles);
		if (RBACLogger.debug()) {
			RBACLogger.log("\tresult:");
			System.out.println(authorizedRoles);
		}
		if (!authorizedRoles.isEmpty()) {
			return true;
		}
		return false;
	}
	
	private Boolean shouldLoadMap() {
		return true;
	}
	
	// setters
	
	public void setPermissionSourceService(
			PermissionSourceService permissionSourceService) {
		this.permissionSourceService = permissionSourceService;
	}
	public String getAccessDeniedPage() {
		return accessDeniedPage;
	}

	public void setAccessDeniedPage(String accessDeniedPage) {
		this.accessDeniedPage = accessDeniedPage;
	}

	public void setRoleSourceService(RoleSourceService roleSourceService) {
		this.roleSourceService = roleSourceService;
	}
}
